/**
 * Copyright (C) 2013 The yydorid-framework project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.yangying.androidframework.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.channels.FileChannel;

import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.util.Log;

/**
 * FileUtil
 * 
 * @author YANGYING
 * 
 * @date 2013-1-10 
 */
public class FileUtil {
	
	private static final String TAG = FileUtil.class.getSimpleName();
	
	public static File updateDir = null;
	public static File updateFile = null;

	/***
	 * 创建文件
	 */
	public static void createFile(String name) {
		if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment
				.getExternalStorageState())) {
			updateDir = new File(SDCardUtil.getAppSDCardPath());
			updateFile = new File(updateDir + File.separator + name + ".apk");

			if (!updateDir.exists()) {
				updateDir.mkdirs();
			}
			if (!updateFile.exists()) {
				try {
					updateFile.createNewFile();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}
	}
	
	public static boolean hasSDCardMounted() {
		return Environment.getExternalStorageState().equals("mounted");
	}

	public static String printSDCardRoot() {
		return Environment.getExternalStorageDirectory().getAbsolutePath();
	}
	
	/**
	 * 向程序内部存储写入文件
	 * 
	 * @param context
	 * @param fileName
	 * @param text
	 */
	public static void writeFile(Context context,String fileName,String text,int mode){
		FileOutputStream fOut= null;
		try {
			fOut = context.openFileOutput(fileName, mode);
			OutputStreamWriter osw = new OutputStreamWriter(fOut);
			osw.write(text);
			osw.flush();
			osw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	/**
	 * 读取内部文件
	 * 
	 * @param context
	 * @param fileName
	 * @return
	 */
	public static FileInputStream readFileFromInternal(Context context,String fileName){
		try {
			return context.openFileInput(fileName);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static FileInputStream readFileInputStream(String filePath){
		File myFile = new File(filePath);
		FileInputStream fIn = null;
		try {
			fIn = new FileInputStream(myFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return fIn;
	}

	public static String readFileExt(String file){
		StringBuilder aBuffer = new StringBuilder();
		File myFile = new File(file);
	    if(myFile.isDirectory() || !myFile.exists()){
	    	Log.e(TAG,"FILE NOT FOUND");
	    	return aBuffer.toString();
	    }
	    
		FileInputStream fIn = null;
		BufferedReader myReader = null;
		String readLine = "";
		try {
			fIn = new FileInputStream(myFile);
			myReader = new BufferedReader(new InputStreamReader(fIn,"UTF-8"));
//			char[] c = new char[(int)myFile.length()];
//			myReader.read(c, 0, (int)myFile.length());
//			aBuffer.append(c);
			char[] buffer = new char[8192];
	        int read;
	        while ((read = myReader.read(buffer)) != -1) {
	        	aBuffer.append(buffer, 0, read);
	        }
//			Log.i(TAG,"abuffer:"+aBuffer.toString());
		} catch (FileNotFoundException e) {
			Log.e(TAG,"FILE NOT FOUND");
			return aBuffer.toString();
		} catch (UnsupportedEncodingException e1) {
			Log.e(TAG,"UnsupportedEncodingException");
			return aBuffer.toString();
		} catch (IOException e) {
			Log.e(TAG,"IO ERROR");
		} finally {
			if(myReader != null)
			try {
				myReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}			
		}
		return aBuffer.toString();
	}
	public static String readFileAsString2(String filePath) {
	    String result = "";
	    File file = new File(filePath);
	    if(file.isDirectory()){
	    	return result;
	    }
	    if ( file.exists() ) {
	        //byte[] buffer = new byte[(int) new File(filePath).length()];
	        FileInputStream fis = null;
	        try {
	            //f = new BufferedInputStream(new FileInputStream(filePath));
	            //f.read(buffer);
	            fis = new FileInputStream(file);
	            BufferedReader br = new BufferedReader(new InputStreamReader(fis,"UTF-8"));
	            
	            char current;
	            while (fis.available() > 0) {
	                current = (char) fis.read();
	                result = result + String.valueOf(current);
	            }
	        } catch (Exception e) {
	            Log.e(TAG, e.toString());
	        } finally {
	            if (fis != null)
	                try {
	                    fis.close();
	                } catch (IOException ignored) {
	            }
	        }
	    }
	    return result;
	}
	public static String readFileAsString(String filePath) {
	    String result = "";
	    File file = new File(filePath);
	    if(file.isDirectory()){
	    	return result;
	    }
	    if ( file.exists() ) {
	        //byte[] buffer = new byte[(int) new File(filePath).length()];
	        FileInputStream fis = null;
	        try {
	            //f = new BufferedInputStream(new FileInputStream(filePath));
	            //f.read(buffer);
	            fis = new FileInputStream(file);
	            char current;
	            while (fis.available() > 0) {
	                current = (char) fis.read();
	                result = result + String.valueOf(current);
	            }
	        } catch (Exception e) {
	            Log.e(TAG, e.toString());
	        } finally {
	            if (fis != null)
	                try {
	                    fis.close();
	                } catch (IOException ignored) {
	            }
	        }
	    }
	    return result;
	}
	
	private void copyAssets(Context context) {
	    AssetManager assetManager = context.getAssets();
	    String[] files = null;
	    try {
	        files = assetManager.list("");
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	    for(String filename : files) {
	        InputStream in = null;
	        OutputStream out = null;
	        try {
	          in = assetManager.open(filename);
	          out = new FileOutputStream(android.os.Environment.getExternalStorageDirectory() +"/" + filename);
	          copyFile(in, out);
	          in.close();
	          in = null;
	          out.flush();
	          out.close();
	          out = null;
	        } catch(IOException e) {
	            e.printStackTrace();
	        }       
	    }
	}
	private void copyFile(InputStream in, OutputStream out) throws IOException {
	    byte[] buffer = new byte[1024];
	    int read;
	    while((read = in.read(buffer)) != -1){
	      out.write(buffer, 0, read);
	    }
	}
	
	/**
	 * copy single file 
	 * @param context
	 * @param fromFile assert中的文件
	 * @param toPath 目标目录
	 * @return
	 */
	public static boolean copySingleFileFromAssert(Context context, String fromFile, String toPath) {
        try {
            int bytesum = 0;
            int byteread = 0;
            InputStream inStream = context.getAssets().open(fromFile);
            File fFile = new File(fromFile);
            Log.i("tf",fFile.getName());
            File toFilePath = new File(toPath);
            toFilePath.mkdirs();
            OutputStream fs = new BufferedOutputStream(new FileOutputStream(toPath+"/"+fFile.getName()));
            byte[] buffer = new byte[8192];
            while ((byteread = inStream.read(buffer)) != -1) {
                bytesum += byteread;
                fs.write(buffer, 0, byteread);
            }
            inStream.close();
            fs.close();
            return true;
        } catch (Exception e) {
        	e.printStackTrace();
            return false;
        }
    }
	
	/**
	 * 复制文件或目录
	 * 
	 * @param context
	 * @param fromAssertPath
	 * @param toPath
	 */
	public static void copyFileOrDir(Context context, String fromAssertPath) {
		String toPath = Environment.getExternalStorageDirectory() + Constant.SLASH + Constant.SDCARD_CACHE_ROOT;
	    AssetManager assetManager = context.getAssets();
	    String assets[] = null;
	    try {
	        assets = assetManager.list(fromAssertPath);
	        if (assets.length == 0) {
	            copyFile(context,fromAssertPath,toPath);
	        } else {
//	            String fullPath = "/data/data/" + this.getPackageName() + "/" + path;
	        	String fullPath = toPath + "/" + fromAssertPath;
	            File dir = new File(fullPath);
	            if (!dir.exists())
	                dir.mkdirs();
	            for (int i = 0; i < assets.length; ++i) {
	                copyFileOrDir(context, fromAssertPath + "/" + assets[i]);
	            }
	        }
	    } catch (IOException ex) {
	        Log.e("tag", "I/O Exception", ex);
	    }
	}
	
	public static void copyFileOrDirWithOption(Context context, String fromAssertPath,boolean force) {
		String toPath = Environment.getExternalStorageDirectory() + Constant.SLASH + Constant.SDCARD_CACHE_ROOT;
	    AssetManager assetManager = context.getAssets();
	    String assets[] = null;
	    try {
	        assets = assetManager.list(fromAssertPath);
	        if (assets.length == 0) {
	            copyFile(context,fromAssertPath,toPath,force);
	        } else {
//	            String fullPath = "/data/data/" + this.getPackageName() + "/" + path;
	        	String fullPath = toPath + "/" + fromAssertPath;
	            File dir = new File(fullPath);
	            if (!dir.exists())
	                dir.mkdirs();
	            for (int i = 0; i < assets.length; ++i) {
	            	copyFileOrDirWithOption(context, fromAssertPath + "/" + assets[i],force);
	            }
	        }
	    } catch (IOException ex) {
	        Log.e("tag", "I/O Exception", ex);
	    }
	}
	
	/**
	 * 复制文件，若目标文件存在，则不复制
	 * 
	 * @param context
	 * @param filename
	 * @param toPath
	 */
	private static void copyFile(Context context, String filename, String toPath) {
	    AssetManager assetManager = context.getAssets();
	    InputStream in = null;
	    OutputStream out = null;
	    try {
	        in = assetManager.open(filename);
//	        String newFileName = "/data/data/" + this.getPackageName() + "/" + filename;
	        String newFileName = toPath + "/" + filename;
	        File file = new File(newFileName);
	        if(file.exists()){
//	        	Log.d(TAG, "exist cache");
	        	return ;
	        }
//	        Log.d(TAG, "do cache");
	        out = new FileOutputStream(newFileName);

	        byte[] buffer = new byte[1024];
	        int read;
	        while ((read = in.read(buffer)) != -1) {
	            out.write(buffer, 0, read);
	        }
	        in.close();
	        in = null;
	        out.flush();
	        out.close();
	        out = null;
	    } catch (Exception e) {
	        Log.e("tag", e.getMessage());
	    }

	}
	/**
	 * 复制文件，若目标文件存在,并且不是强制覆盖，则不复制
	 * 
	 * @param context
	 * @param filename
	 * @param toPath
	 */
	private static void copyFile(Context context, String filename, String toPath,boolean force) {
	    AssetManager assetManager = context.getAssets();
	    InputStream in = null;
	    OutputStream out = null;
	    try {
	        in = assetManager.open(filename);
//	        String newFileName = "/data/data/" + this.getPackageName() + "/" + filename;
	        String newFileName = toPath + "/" + filename;
	        File file = new File(newFileName);
	        if(file.exists() && !force){
//	        	Log.d(TAG, "exist cache");
	        	return ;
	        }
//	        Log.d(TAG, "do cache");
	        out = new FileOutputStream(newFileName);

	        byte[] buffer = new byte[1024];
	        int read;
	        while ((read = in.read(buffer)) != -1) {
	            out.write(buffer, 0, read);
	        }
	        in.close();
	        in = null;
	        out.flush();
	        out.close();
	        out = null;
	    } catch (Exception e) {
	        Log.e("tag", e.getMessage());
	    }

	}
	
    public static void copyFile(File src, File dst) throws IOException {
        FileChannel inChannel = new FileInputStream(src).getChannel();
        FileChannel outChannel = new FileOutputStream(dst).getChannel();
        try {
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } finally {
            if (inChannel != null)
            inChannel.close();
            if (outChannel != null)
            outChannel.close();
        }
    }

    public static boolean copyCacheFile(Context context,String cacheFileName){
    	boolean ret = false;
	    AssetManager assetManager = context.getAssets();
	    InputStream is = null;
	    OutputStream fs = null;
	    try {
			is = assetManager.open(cacheFileName);
            File toFilePath = new File(Environment.getExternalStorageDirectory() 
        			+ File.separator + Constant.SDCARD_CACHE_ROOT);
            toFilePath.mkdirs();
            int byteread;
            fs = new BufferedOutputStream(new FileOutputStream(Environment.getExternalStorageDirectory() 
        			+ File.separator + Constant.SDCARD_CACHE_ROOT
    				+ File.separator + Constant.CACHE_FILE));
            byte[] buffer = new byte[10240];
            while ((byteread = is.read(buffer)) != -1) {
                fs.write(buffer, 0, byteread);
            }
            ret = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				if(is != null){
					is.close();
				}
				if(fs != null){
					fs.close();	
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			//cant close 
//			if(assetManager != null){
//				assetManager.close();
//			}
		}
	    return ret;
    }
    public static boolean unzipCacheFile(boolean forceCopy){
    	boolean ret = false;
		InputStream isZip = null;
		File file = new File(Environment.getExternalStorageDirectory() 
    			+ File.separator + Constant.SDCARD_CACHE_ROOT
				+ File.separator + Constant.CACHE_FILE);
		FileInputStream fis = FileUtil.readFileInputStream(file.getAbsolutePath());
		isZip = new BufferedInputStream(fis);
        if(isZip != null){
        	boolean flag = ZipUtils.unzip(isZip, Environment.getExternalStorageDirectory() 
        			+ File.separator + Constant.SDCARD_CACHE_ROOT,forceCopy);
//        	Log.d(TAG,"unzip new zip:" + flag);
        	boolean dflag = file.delete();
			if(!dflag){
//				Log.e(TAG, "DELETE CACHE ERROR!" + file.getName());
				ret = false;
	        	return ret;
			} else {
//				Log.d(TAG, "DELETE TEMP ZIP SUCCESS!" + file.getName());
				ret = true;
			}
        }
    	return ret;
    }
}
